package com.bcxj.serviceorder.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bcxj.internalcommon.constant.CommonStatusEnum;
import com.bcxj.internalcommon.constant.IdentityConstant;
import com.bcxj.internalcommon.constant.OrderConstant;
import com.bcxj.internalcommon.dto.OrderRequest;
import com.bcxj.internalcommon.dto.ResponseResult;
import com.bcxj.internalcommon.entity.Car;
import com.bcxj.internalcommon.entity.OrderInfo;
import com.bcxj.internalcommon.response.OrderDriverResponse;
import com.bcxj.internalcommon.response.TerminalResponse;
import com.bcxj.internalcommon.response.TrsearchResponse;
import com.bcxj.internalcommon.util.RedisPrefixUtils;
import com.bcxj.serviceorder.client.ServiceDriverUserClient;
import com.bcxj.serviceorder.client.ServiceMapClient;
import com.bcxj.serviceorder.client.ServicePriceClient;
import com.bcxj.serviceorder.client.ServiceSsePushClient;
import com.bcxj.serviceorder.mapper.OrderInfoMapper;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSON;
import net.sf.json.JSONObject;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * ClassName: OrderInfoService
 * Package: com.bcxj.serviceorder.service
 * Description:
 *
 * @Author BCXJ
 * @Create 2024/11/9 20:09
 * @Version 1.0
 * @Since 1.0
 */
@Service
@Slf4j
public class OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private ServicePriceClient servicePriceClient;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ServiceDriverUserClient serviceDriverUserClient;
    @Autowired
    private ServiceMapClient serviceMapClient;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private ServiceSsePushClient serviceSsePushClient;

    /**
     * 增加订单
     *
     * @param orderRequest
     * @return
     */
    public ResponseResult add(OrderRequest orderRequest) {
        // 1 订单的信息判断

        // 1.1. 计价规则是否存在
        if (isExists(orderRequest.getFareType())) {
            return ResponseResult.fail(CommonStatusEnum.CITY_SERVICE_NOT_SERVICE);
        }

        // 1.2. 订单是否是最新的
        ResponseResult<Boolean> isNewRes = servicePriceClient.isNew(orderRequest.getFareType(), orderRequest.getFareVersion());
        if (Boolean.FALSE.equals(isNewRes.getData())) {
            return ResponseResult.fail(CommonStatusEnum.PRICE_RULE_CHANGED);
        }

        // 1.3. 城市是否有司机提供服务
        ResponseResult<Boolean> alailableDriver = serviceDriverUserClient.isAlailableDriver(orderRequest.getAddress());
        if (Boolean.FALSE.equals(alailableDriver.getData())) {
            return ResponseResult.fail(CommonStatusEnum.CITY_DRIVER_EMPTY);
        }

        // 1.3. 是否有正在进行的订单
        if (isOrderGoingOn(orderRequest.getPassengerId())) {
            return ResponseResult.fail(CommonStatusEnum.ORDER_GOING_ON);
        }

        // 1.4 是否是黑名单终端(这里的黑名单指的是多次下订单的同一个用户)
        if (isBlackDevice(orderRequest.getDeviceCode())) {
            return ResponseResult.fail(CommonStatusEnum.DEVICE_IS_BLACK);
        }

        // 2 下订单
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderRequest, orderInfo);
        // 补全其他的信息
        orderInfo.setOrderStatus(OrderConstant.START);
        LocalDateTime now = LocalDateTime.now();
        orderInfo.setGmtCreate(now);
        orderInfo.setGmtModified(now);

        orderInfoMapper.insert(orderInfo);

        // 订单派单
        // 定时任务简单的实现
        for (int i = 0; i < 6; i++) {
            int res = dispatchRealTimeOrder(orderInfo);
            if (1 == res) {
                break;
            }
            if(i == 5) {
                // 订单状态设置为失效，其实我觉得这样设置并不合理
                orderInfo.setOrderStatus(OrderConstant.ORDER_INVALID);
                orderInfoMapper.updateById(orderInfo);
            }
            try {
                // 休眠一段时间再次尝试·， 这里的尝试是同步进行的哦
                Thread.sleep(200);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        return ResponseResult.success();
    }


    /**
     * 订单的派发
     *
     * @param orderInfo
     * @return 返回1表示派单成功，否则表示派单失败
     */
    public int dispatchRealTimeOrder(OrderInfo orderInfo) {
        log.info("尝试循环查找终端");
        // 获取经纬度的信息
        String depLatitude = orderInfo.getDepLatitude(); // 经度
        String depLongitude = orderInfo.getDepLongitude(); // 纬度
        String center = depLongitude + "," + depLatitude;

        // 获取周边搜索的信息 (高德免费搜索范围在 1 - 5 km内)
        ArrayList<Integer> radiusList = new ArrayList<>();
        radiusList.add(2000);
        radiusList.add(4000);
        radiusList.add(5000);

        // 周边搜索
        for (Integer radius : radiusList) {
            // 搜索周边的距离
            ResponseResult<List<TerminalResponse>> arroundsearch = serviceMapClient.arroundsearch(center, radius.toString());
            log.info("在范围为" + radius + " 搜索终端，结果为: " + arroundsearch.getData());
            // 获取具体的字段的信息
            List<TerminalResponse> data = arroundsearch.getData();
//            List<TerminalResponse> data = new ArrayList<>(); // 了测试才循环查找才加上这一行的。
            if (data != null && !data.isEmpty()) {
                for (TerminalResponse datum : data) {
                    log.info("终端的信息为 : tid-" + datum.getTid() + " " + "carId-" + datum.getCarId());
                    // 查找车辆对应的可用的司机的信息
                    ResponseResult<OrderDriverResponse> availableDriver = serviceDriverUserClient.getAvailableDriver(datum.getCarId().toString());
                    OrderDriverResponse orderDriverData = availableDriver.getData();
                    if (null == orderDriverData) {
                        log.info("在公里范围内：" + radius + "没有找到可用司机");
                        continue;
                    } else {
                        // 比对车型，乘客下订单可以选择自己的车类型
                        if (!orderInfo.getVehicleType().trim().equals(orderDriverData.getVehicleType().trim())) {
                            log.info("车型不符合");
                            continue;
                        }

                        // 解析司机的信息
                        log.info("在公里范围内：" + radius + "找到司机，信息为：" + orderDriverData);
                        // 获取司机的id
                        Long driverId = orderDriverData.getDriverId();

                        // 加redisson分布式锁
                        RLock lock = redissonClient.getLock((driverId + "").intern());
                        lock.lock(); // 没有获取锁会阻塞

                        // 司机是否有订单
                        if (isDriverOrderGoingon(driverId) > 0) {
                            lock.unlock();
                            continue;
                        }

                        // 封装订单的消息，给司机派单
                        orderInfo.setDriverId(orderDriverData.getDriverId());
                        orderInfo.setDriverPhone(orderDriverData.getDriverPhone());
                        orderInfo.setCarId(orderDriverData.getCarId());
                        orderInfo.setReceiveOrderCarLongitude(datum.getLongitude());
                        orderInfo.setReceiveOrderCarLatitude(datum.getLatitude());
                        orderInfo.setReceiveOrderTime(LocalDateTime.now());
                        orderInfo.setLicenseId(orderDriverData.getLicenseId());
                        orderInfo.setVehicleNo(orderDriverData.getVehicleNo());
                        orderInfo.setOrderStatus(OrderConstant.DRIVER_RECEIVE_ORDER);

                        // 更新订单的信息
                        orderInfoMapper.updateById(orderInfo);

                        // 消息推送司机端
                        JSONObject driverContent = new JSONObject();
                        driverContent.put("orderId", orderInfo.getId());
                        driverContent.put("passengerId", orderInfo.getPassengerId());
                        driverContent.put("passengerPhone", orderInfo.getPassengerPhone());
                        driverContent.put("departure", orderInfo.getDeparture());
                        driverContent.put("depLongitude", orderInfo.getDepLongitude());
                        driverContent.put("depLatitude", orderInfo.getDepLatitude());
                        driverContent.put("destination", orderInfo.getDestination());
                        driverContent.put("destLongitude", orderInfo.getDestLongitude());
                        driverContent.put("destLatitude", orderInfo.getDestLatitude());

                        serviceSsePushClient.push(driverId.toString(), IdentityConstant.DRIVER_IDENTITY, driverContent.toString());

                        // 消息推送给乘客
                        JSONObject passengerContent = new JSONObject();
                        passengerContent.put("orderId", orderInfo.getId());
                        passengerContent.put("driverId", orderInfo.getDriverId());
                        passengerContent.put("driverPhone", orderInfo.getDriverPhone());
                        passengerContent.put("vehicleNo", orderInfo.getVehicleNo());
                        // 查看车辆服务
                        Car car = serviceDriverUserClient.getCar(orderInfo.getCarId().toString()).getData();
                        passengerContent.put("brand", car.getBrand());
                        passengerContent.put("model", car.getModel());
                        passengerContent.put("vehicleColor", car.getVehicleColor());
                        passengerContent.put("receiveOrderCarLongitude", orderInfo.getReceiveOrderCarLongitude());
                        passengerContent.put("receiveOrderCarLatitude", orderInfo.getReceiveOrderCarLatitude());
                        serviceSsePushClient.push(orderInfo.getPassengerId().toString(), IdentityConstant.PASSENGER_IDENTITY, passengerContent.toString());
                        lock.unlock();
                        return 1;
                    }

                }
            }

        }
        return 0;
    }


    /**
     * 获取司机正在进行的订单数
     *
     * @param driverId
     * @return
     */
    private int isDriverOrderGoingon(Long driverId) {
        // 查询司机正在进行的订单
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getDriverId, driverId)
                .and(wrapper -> wrapper.eq(OrderInfo::getOrderStatus, OrderConstant.DRIVER_RECEIVE_ORDER).or()
                        .eq(OrderInfo::getOrderStatus, OrderConstant.DRIVER_TO_PICK_UP_PASSENGER).or()
                        .eq(OrderInfo::getOrderStatus, OrderConstant.DRIVER_ARRIVED_DEPARTURE).or()
                        .eq(OrderInfo::getOrderStatus, OrderConstant.PICK_UP_PASSENGER));

        Integer count = orderInfoMapper.selectCount(queryWrapper);

        log.info("司机：" + driverId + "正在进行的订单数为：" + count);

        return count;
    }


    /**
     * 计价规则是否存在
     *
     * @param fareType
     * @return
     */
    private boolean isExists(String fareType) {
        // 解析信息
        String[] split = fareType.split("\\$");
        String address = split[0];
        String vehicleType = split[1];

        ResponseResult<Boolean> booleanResponseResult = servicePriceClient.ifExists(address, vehicleType);

        return !booleanResponseResult.getData();
    }


    /**
     * 是否是黑名单终端
     *
     * @param deviceCode
     * @return
     */
    private boolean isBlackDevice(String deviceCode) {
        // 查看key是否存在
        Boolean b = redisTemplate.hasKey(RedisPrefixUtils.blackDeviceCodePrefix + deviceCode);

        // 存在
        if (Boolean.TRUE.equals(b)) {
            int num = Integer.parseInt(Objects.requireNonNull(redisTemplate.opsForValue().get(RedisPrefixUtils.blackDeviceCodePrefix + deviceCode)));
            if (num > 2) {
                return true;
            }

            redisTemplate.opsForValue().increment(RedisPrefixUtils.blackDeviceCodePrefix + deviceCode);
            return false;
        }

        // 不存在
        redisTemplate.opsForValue().set(RedisPrefixUtils.blackDeviceCodePrefix + deviceCode, "1", 1, TimeUnit.HOURS);

        return false;
    }


    /**
     * 是否有正在进行的订单
     *
     * @param passengerId
     * @return
     */
    private boolean isOrderGoingOn(Long passengerId) {

        List<OrderInfo> orderInfos = orderInfoMapper.selectList(new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getPassengerId, passengerId)
                .and(wrapper -> wrapper.eq(OrderInfo::getOrderStatus, OrderConstant.START).or()
                        .eq(OrderInfo::getOrderStatus, OrderConstant.DRIVER_RECEIVE_ORDER).or()
                        .eq(OrderInfo::getOrderStatus, OrderConstant.DRIVER_TO_PICK_UP_PASSENGER).or()
                        .eq(OrderInfo::getOrderStatus, OrderConstant.DRIVER_ARRIVED_DEPARTURE).or()
                        .eq(OrderInfo::getOrderStatus, OrderConstant.PICK_UP_PASSENGER).or()
                        .eq(OrderInfo::getOrderStatus, OrderConstant.PASSENGER_GETOFF).or()
                        .eq(OrderInfo::getOrderStatus, OrderConstant.TO_START_PAY)));

        return orderInfos != null && !orderInfos.isEmpty();
    }


    /**
     * 司机开始去接乘客(还未接到，准备出发)
     *
     * @param orderRequest
     * @return
     */
    public ResponseResult toPickUpPassenger(OrderRequest orderRequest) {
        // 属性的拷贝
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderRequest, orderInfo);
        // 信息补充
        orderInfo.setId(orderRequest.getOrderId());
        // 修改订单的状态为司机接乘客
        orderInfo.setOrderStatus(OrderConstant.DRIVER_TO_PICK_UP_PASSENGER);

        orderInfoMapper.updateById(orderInfo);

        return ResponseResult.success();

    }


    /**
     * 司机到达乘客的出发地
     *
     * @param orderRequest
     * @return
     */
    public ResponseResult arrivedDeparture(OrderRequest orderRequest) {
        OrderInfo orderInfo = new OrderInfo();
        // 更新司机的状态，以及司机到达出发点的时间
        orderInfo.setId(orderRequest.getOrderId());
        orderInfo.setDriverArrivedDepartureTime(LocalDateTime.now());
        // 订单的状态的更新
        orderInfo.setOrderStatus(OrderConstant.DRIVER_ARRIVED_DEPARTURE);
        orderInfoMapper.updateById(orderInfo);
        return ResponseResult.success();
    }


    /**
     * 司机接受到乘客
     *
     * @param orderRequest
     * @return
     */
    public ResponseResult pickUpPassenger(OrderRequest orderRequest) {
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderRequest, orderInfo);
        orderInfo.setId(orderRequest.getOrderId());
        orderInfo.setPickUpPassengerTime(LocalDateTime.now());
        // 设置订单的状态
        orderInfo.setOrderStatus(OrderConstant.PICK_UP_PASSENGER);
        orderInfoMapper.updateById(orderInfo);
        return ResponseResult.success();
    }


    /**
     * 乘客到达目的地/乘客下车
     *
     * @param orderRequest
     * @return
     */
    public ResponseResult orderGetoff(OrderRequest orderRequest) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderRequest.getOrderId());
        orderInfo.setPassengerGetoffLatitude(orderRequest.getPassengerGetoffLatitude());
        orderInfo.setPassengerGetoffLongitude(orderRequest.getPassengerGetoffLongitude());

        // 补全订单的信息
        orderInfo.setId(orderRequest.getOrderId());
        orderInfo.setPassengerGetoffTime(LocalDateTime.now());
        orderInfo.setOrderStatus(OrderConstant.PASSENGER_GETOFF);

        // 获取车辆的信息
        ResponseResult<Car> car = serviceDriverUserClient.getCar(orderInfo.getCarId().toString());
        String tid = car.getData().getTid();

        // 获取订单的总时长和总距离
        // 获取开始时间 & 结束时间 精确到毫秒值
        long starttime = orderInfo.getPickUpPassengerTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        long endtime = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        TrsearchResponse trsearch = serviceMapClient.trsearch(tid, starttime, endtime).getData();

        orderInfo.setDriveMile(trsearch.getDistance());
        orderInfo.setDriveTime(trsearch.getTime());

        // 计算价格
        ResponseResult<Double> doubleResponseResult = servicePriceClient.calculatePrice(trsearch.getDistance().toString(), trsearch.getTime().toString(),
                orderInfo.getFareType(), orderInfo.getFareVersion().toString());

        orderInfo.setPrice(doubleResponseResult.getData());
        // 更新订单
        orderInfoMapper.updateById(orderInfo);

        return ResponseResult.success();
    }

    /**
     * 乘客支付订单/订单完成
     *
     * @param orderRequest
     * @return
     */
    public ResponseResult pay(OrderRequest orderRequest) {
        // 老师这里的采用先查询订单然后更新, 其实可以直接更新的
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderRequest, orderInfo);
        orderInfo.setOrderStatus(OrderConstant.SUCCESS_PAY);
        orderInfo.setId(orderRequest.getOrderId());
        orderInfoMapper.updateById(orderInfo);
        return ResponseResult.success();
    }


    /**
     * 订单的取消
     *
     * @param orderId
     * @param identity
     * @return
     */
    public ResponseResult cancel(String orderId, String identity) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        // 获取订单的状态
        Integer orderStatus = orderInfo.getOrderStatus();
        int cancelType = 0;
        if (IdentityConstant.PASSENGER_IDENTITY.equals(identity)) {
            // 乘客取消订单
            cancelType = passengerCancelOrder(orderStatus, orderInfo);
            orderInfo.setCancelOperator(1);
        } else if(IdentityConstant.DRIVER_IDENTITY.equals(identity)) {
            // 司机取消订单
            cancelType = driverCancelOrder(orderStatus, orderInfo);
            orderInfo.setCancelOperator(2);
        }


        if (cancelType == 0) {
            orderInfo.setOrderStatus(OrderConstant.CANCEL);
            orderInfo.setCancelTime(LocalDateTime.now());
            // 更新数据库数据
            orderInfoMapper.updateById(orderInfo);
            return ResponseResult.success();
        } else {
            return ResponseResult.fail(CommonStatusEnum.ORDER_CACEL_ERROR);
        }
    }

    /**
     * 司机取消订单
     *
     * @param orderStatus
     * @param orderInfo
     * @return
     */
    private int driverCancelOrder(Integer orderStatus, OrderInfo orderInfo) {
        Integer cacelType = 0;
        switch (orderStatus) {
            case OrderConstant.DRIVER_RECEIVE_ORDER:
                // 司机接订单
            case OrderConstant.DRIVER_TO_PICK_UP_PASSENGER:
                // 司机去接乘客
            case OrderConstant.DRIVER_ARRIVED_DEPARTURE:
                // 司机到达出发点
                LocalDateTime receiveOrderTime = orderInfo.getReceiveOrderTime();
                LocalDateTime now = LocalDateTime.now();
                if (ChronoUnit.MINUTES.between(receiveOrderTime, now) > 1) {
                    orderInfo.setCancelTypeCode(OrderConstant.CANCEL_DRIVER_ILLEGAL);
                } else {
                    orderInfo.setCancelTypeCode(OrderConstant.CANCEL_DRIVER_BEFORE);
                }
                break;
            default:
                cacelType = 1;
                log.info("订单乘客无法取消");
                break;
        }

        return cacelType;
    }

    /**
     * 乘客取消订单
     *
     * @param orderStatus
     * @param orderInfo
     * @return 0表示成功，1表示无法修改
     */
    private int passengerCancelOrder(Integer orderStatus, OrderInfo orderInfo) {
        Integer cacelType = 0;
        switch (orderStatus) {
            case OrderConstant.START:
                orderInfo.setCancelTypeCode(OrderConstant.CALCEL_PASSENGER_BEFORE);
                break;
            case OrderConstant.DRIVER_RECEIVE_ORDER:
                // 判断时间的区间
                LocalDateTime receiveOrderTime = orderInfo.getReceiveOrderTime();
                LocalDateTime now = LocalDateTime.now();
                if (ChronoUnit.MINUTES.between(receiveOrderTime, now) > 1) {
                    orderInfo.setCancelTypeCode(OrderConstant.CANCEL_PASSENGER_ILLEGAL);
                } else {
                    orderInfo.setCancelTypeCode(OrderConstant.CALCEL_PASSENGER_BEFORE);
                }
                break;
            case OrderConstant.DRIVER_TO_PICK_UP_PASSENGER:
            case OrderConstant.DRIVER_ARRIVED_DEPARTURE:
                orderInfo.setCancelTypeCode(OrderConstant.CANCEL_PASSENGER_ILLEGAL);
                break;
            default:
                cacelType = 1;
                log.info("订单乘客无法取消");
                break;
        }

        return cacelType;
    }

    /**
     * 司机发起收款
     * @param orderRequest
     * @return
     */
    public ResponseResult pushPayInfo(OrderRequest orderRequest) {
        Long orderId = orderRequest.getOrderId();
        // 查询订单信息
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        // 更改订单状态
        orderInfo.setOrderStatus(OrderConstant.TO_START_PAY);

        // 推送消息
        JSONObject message = new JSONObject();
        message.put("orderId", orderId);
        message.put("price", orderInfo.getPrice());
        serviceSsePushClient.push(orderInfo.getPassengerId().toString(), IdentityConstant.PASSENGER_IDENTITY, message.toString());
        orderInfoMapper.updateById(orderInfo);
        return ResponseResult.success();
    }
}
